/* Copyright (c) 2022 渝州大数据实验室
 *
 * Lanius is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package org.yzbdl.lanius.orchestrate.common.exception;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.yzbdl.lanius.orchestrate.common.exception.runtime.BusinessException;
import org.yzbdl.lanius.orchestrate.common.result.ResultObj;
import org.yzbdl.lanius.orchestrate.common.result.ResultTypeEnum;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


/**
 *
 * @author chenjunhao@yzbdl.ac.cn
 * @date 2019/9/2
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger  =  LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public ResultObj paramsExceptionHandler(ConstraintViolationException e) {
        List<String> errorList = new ArrayList<>();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            StringBuilder message = new StringBuilder();
            Path path = violation.getPropertyPath();
            String[] pathArr = path.toString().split("\\.");
            String msg = message.append(pathArr[1]).append(violation.getMessage()).toString();
            errorList.add(msg);
        }
        return ResultObj.error(errorList);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResultObj bodyParamsException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<ParamErrorVO> errorList = new ArrayList<>();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorList.add(ParamErrorVO.builder()
                    .fieldName(fieldError.getField())
                    .errorMsg(fieldError.getDefaultMessage())
                    .build());
        }
        return ResultObj.error(errorList);
    }

    /**
     * 业务异常
     * @param request 请求对象
     * @param e 异常对象
     * @return 前端封装对象
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResultObj businessExceptionHandler(HttpServletRequest request,BusinessException e) {
        return ResultObj.error(ResultTypeEnum.SERVICE_ERROR,e.getErrMsg());
    }

    /**
     * 捕获AuthenticationException异常
     * @param request 请求对象
     * @param e 异常对象
     * @return 前端封装对象
     */
    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public ResultObj authenticationExceptionHandler(HttpServletRequest request,AuthenticationException e) {
        return ResultObj.error(ResultTypeEnum.AUTHORIZED_FORBID,e.getMessage());
    }

    /**
     * 捕获HttpRequestMethodNotSupportedException异常
     * @param request 请求对象
     * @param e 异常对象
     * @return 前端封装对象
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ResponseBody
    public ResultObj methodNotAllowedExceptionHandler(HttpServletRequest request,HttpRequestMethodNotSupportedException e) {
        return ResultObj.error(ResultTypeEnum.PARAM_ERROR,e.getMessage());
    }

    /**
     * 默认异常捕获，上面异常没走的话走这个。
     * @param request 请求对象
     * @param e 异常类
     * @return 前端封装对象
     */
    @ExceptionHandler()
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultObj exceptionHandler(HttpServletRequest request,Exception e) {
        request.getMethod();
        logger.error("出现系统错误！",e);
        return ResultObj.error(ResultTypeEnum.SERVICE_ERROR,"出现系统错误！");
    }


}

